package org.langcom.state;

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


public abstract class AbstractAutomataState<T> implements IAutomataState<T> {

	protected T input;
	protected IState currentState;
	protected List<IState> stateList = new ArrayList<IState>();
	protected Map<IState, List<IStateTransition>> transitionFromMap = new HashMap<IState, List<IStateTransition>>();
	protected Map<IState, List<IStateTransition>> transitionToMap = new HashMap<IState, List<IStateTransition>>();
	protected List<PropertyChangeListener> listeners = new ArrayList<PropertyChangeListener>();
	
	//states
	
	//actions
	
	//transitions
	
	public List<IState> getAllStates() {
		return stateList;
	}
	
	public void addState(IState state) {
		stateList.add(state);
	}
	
	public void addStateTransition(IStateTransition transition) {
		addTransitionToMap(transitionFromMap,transition,transition.getFromState());
		addTransitionToMap(transitionToMap,transition,transition.getToState());
	}

	private void addTransitionToMap(Map<IState, List<IStateTransition>> targetMap,IStateTransition transition,IState state) {
		List<IStateTransition> list = targetMap.get(state);
		if(list == null) {
			list = new ArrayList<IStateTransition>();
			targetMap.put(state, list);
		}
		list.add(transition);
	}
	
	public Map<IState, List<IStateTransition>> getTransitionFromMap() {
		return transitionFromMap;
	}

	public Map<IState, List<IStateTransition>> getTransitionToMap() {
		return transitionToMap;
	}

	public IState getCurrentState() {
		checkState();
		return currentState;
	}

	protected boolean checkStateTransitions(IStateTransition... stateTransitions) {
		for (IStateTransition transition : stateTransitions) {
			if (transition.checkState()) {
				currentState = transition.getToState();
				firePropertyChanged(new TransitionEvent(this, transition.getFromState(), transition
					.getToState()));
				return true;
			}else {
				currentState = transition.getFromState();
			}
		}
		return false;
	}

	public void addChangeListener(PropertyChangeListener changeListener) {
		listeners.add(changeListener);
	}

	public void firePropertyChanged(PropertyChangeEvent event) {
		for (PropertyChangeListener changeListener : listeners) {
			changeListener.propertyChange(event);
		}
	}

	public void removeChangeListener(PropertyChangeListener changeListener) {
		listeners.remove(changeListener);
	}

	public T getInput() {
		return input;
	}

	public void setInput(T input) {
		this.input = input;
	}

}


